--[[
	Primary Library for Jelly Baby.
	Written by: Adult

	GateKeeper FacePunch thread: http://www.facepunch.com/showthread.php?t=695636
	MySQLOO FacePunch thread: http://facepunch.com/showthread.php?t=1220537

	IF SOMETHING CREATES AN ERROR, COPY THE ERROR, COMMENT OUT THE LINES, AND PUT THE ERROR IN THE COMMENT.

]]-- 

-- Faster access to globals and built-in libraries
local require = require 
local ConVarExists = ConVarExists 
local CreateConVar = CreateConVar 
local string = string 
local ChatPrint = ChatPrint 
local os = os 
local tostring = tostring 
local tonumber = tonumber 
local type = type 
local SERVER = SERVER 
local CLIENT = CLIENT 

-- Load GateKeeper and MySQLOO
require( "gatekeeper" ) 
require( "mysqloo" )

local mysqloo = mysqloo 
local gatekeeper = gatekeeper



--[[ 
	Logging functions
		-- admin.log( tblVals ) - See LogData table structure
]]--

-- Log stuff to the database
function admin.log( str, tblLog )
	if not GetConVar( "jb_log" ) then return end

	-- Format the table so it can be logged properly.
	local admin, adminsid, cmd = tblLog.admin, tblLog.adminsteamid, tblLog.cmd
	local target, targetsid = tblLog.target, tblLog.targetsteamid
	local p1, p2, p3 = tblLog.param1, tblLog.param2, tblLog.param3
	local vals = admin.toInsert( admin, adminsid, cmd, target, targetsid, p1, p2, p3 )

	if admin.db then
		admin.db:query( "INSERT INTO LogData VALUES " .. vals )
	end

	return vals
end


---------------------------------------------------------

--[[
	MySQL Helper functions
		-- admin.toInsert( ... )      -- Converts given parameters into a formatted string for INSERT query
		-- admin.toUpdate( ... )      -- Converts given parameters into a formatted string for UPDATE query
		-- admin.testDatabase()       -- Tests database to see if it's currently set up.
		-- admin.disconnectDatabase() -- Disconnects the current database(s)

]]--

-- Function to preformat tables to work with INSERT queries.
function admin.toInsert( ... )
	local args = { ... }

	local ret = '('

	for i=1,#args do
		ret = ret .. args[i] .. ','
	end

	ret = ret .. ')'
	
	return ret
end

-- Function to preformat strings to work with UPDATE queries.
function admin.toUpdate( ... )
	local columns = { "SteamID", "LastName", "Rank", "PlayTime", "LastConnect" }
	local args = { ... }

	local ret = ""

	for i=1,#columns do
		ret = ret .. columns[i] .. "='" .. args[i] .. "'"
	end

	return ret 
end

function admin.testDatabase()
	if #player.GetAll() >= 1 then
		local q = admin.db:query( "SELECT * FROM UserData" )

		function q:onSuccess( data )
			MsgC( Color( 0, 255, 0), "Test query successful!" )
		end
		
		function q:onError( err, sql )
			MsgC( Color( 255, 0, 0), "Test query failed! Database not setup!" )
			MsgC( Color( 255, 0, 0), "Please run the database_setup.sql to set up the database!" )

			admin.disconnectDatabase()
		end
	end
end

-- Close database connection.
function admin.disconnectDatabase()
	-- Close all queries pls.
	mysqloo.abortAllQueries()

	-- Apparently there's no disconnect function for mysql...
end

------------------------------------------------------------------
--[[
	Kick/Ban functions
		-- admin.kick( ply, reason )          -- Obvious is obvious
		-- admin.addBan( caller, target, targetsid, reason, length/time) -- ban pls
		-- admin.checkActiveBans( steamid )   -- Check active bans
		-- admin.checkInactiveBans( steamid ) -- Check old bans
]]--

-- Kick that faggot
function admin.kick( ply, reason )
	if type( ply ) == "Player" then
 		gatekeeper.Drop( ply:UserID(), reason )
 	elseif type( ply ) == "String" then
 		local target = admin.findPlayerByName( ply )
 		if IsValid( target ) then
 			gatekeeper.Drop( target:UserID(), reason )
 		end
 	end
end

-- If this errors out, just comment it out, please do not edit.
-- Ban function, preferably uses Unix Epoch times for the time,
-- but can use preformatted times.

-- NOT FINISHED, DO NOT CALL. IT WILL BREAK EVERYTHING. kthx.
function admin.addBan( caller, target, target_sid, reason, length )
	local caller_sid = ''
	local caller_name = ''

	if caller and not caller:IsValid() then 
		caller_sid = "Console"
		caller_name = "Console"
	else
		caller_sid = caller:SteamID()
		caller_name = caller:Name()
	end
	
	if not target then target = nil else admin.kick( target, reason ) end
	
	if type( length ) ~= "number" then
		-- table conversion, must do testing.
	end

	local val = admin.toInsert( target_sid, time, reason, 0, caller_name, caller_sid )

	admin.db:query( "INSERT INTO ActiveBans VALUES " .. val )
end

-- Checks the active bans for the steam id
function admin.checkActiveBans( steamid )
	local steamid = string.upper( steamid )

	local ret = {}

	local q = admin.db:query( "SELECT * FROM ActiveBans WHERE SteamID='" .. steamid .. "'" )

	function q:onSuccess( data )
		ret = data 
	end
	
	function q:onError( data )
		ret = nil 
	end

	return ret 
end

-- Checks oldman bans for steam id
function admin.checkInactiveBans( steamid )
	local steamid = string.upper( steamid )

	local ret = {}

	local q = admin.db:query( "SELECT * FROM InactiveBans WHERE SteamID='" .. steamid .. "'" )

	function q:onSuccess( data )
		ret = data 
	end
	
	function q:onError( data )
		ret = nil 
	end
	
	return ret 
end

-----------------------------------------------------------------

--[[
	User Functions, the functions used edit UserData
		-- admin.newUserData( steamid, lastname, rank, playtime, lastconnect )  -- Creates new entry in UserData table
		-- admin.editUserData( steamid, lastname, rank, playtime, lastconnect ) -- Edits existing UserData table
]]--
function admin.newUserData( steamid, lastname, rank, playtime, lastconnect )
	local val = admin.toInsert( steamid, lastname, rank, playtime )

	local q = admin.db:query( "INSERT INTO UserData VALUES " .. val )
end

function admin.editUserData( steamid, lastname, rank, playtime, lastconnect )
	local val = admin.toUpdate( steamid, lastname, rank, playtime, lastconnect )

	local q = admin.db:query( "UPDATE UserData SET " .. val .. " WHERE SteamID='" .. steamid .. "'" )
end
----------------------------------------------------------------

--[[
	Rank functions, server only.
		-- admin.changeRank( plyPlayer, strRank ) returns: bool success
]]--

function admin.changeRank( ply, newrank )
	-- Don't wanna do this shit to an invalid player
	if not ply:IsValid() then return false end

	if type( newrank ) == "number" then
		MsgC( Color( 255, 0, 0 ), "Although ranks have numerical values, please use strings." )
		return false
	end
	
	local old = ply.rank

	-- If it's already that rank, pls.
	if old == newrank then
		return true
	end

	ply.rank = newrank or admin.getRankValue( newrank )

	table.remove( admin.ranks[ old ], ply:SteamID() )

	return true
end

--------------------------------------------------------------

--[[
	Console Commands
]]--

-- I have no idea what I'm doing here.
-- Add console command
function admin.addConcommand( command, access, callback, chatcmd )
	admin.cmd[ command ] = callback
end

---------------------------------------------------------------
--[[
	Messaging Functions
		-- admin.msgAll( strText )
		-- admin.msgAllC( ... ) - Serverside chat.AddText
]]--


function admin.msgAll( text )
	-- net :3
	util.AddNetworkString( "adminMsgAll" )

	net.Start( "adminMsgAll" )
		net.WriteString( text )
	net.Broadcast()

	print( text )
end

function admin.msgAllC( ... )
	-- Make it a table for simplicity's sake
	local args = { ... }

	-- Yay net
	util.AddNetworkString( "adminMsgAllC" )

	net.Start( "adminMsgAllC" )
		net.WriteTable( args )
	net.Broadcast()
end

function admin.msgPly( ply, text )
	util.AddNetworkString( "adminMsgPly" )

	net.Start( "adminMsgPly" )
		net.WriteString( text )
	net.Send( ply )
end

function admin.msgPlyC( ... )
	local args = { ... }

	util.AddNetworkString( "adminMsgPlyC" )

	net.Start( "adminMsgPlyC" )
		net.WriteTable( args )
	net.Send( ply )
end